//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT||LIC==GOOGLE

/**
 * @addtogroup FXCRT
 * @{
 */

/**
 * @file
 * @brief Basic data types
 */

//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FX_BASIC_H_
#define _FX_BASIC_H_

/* System dependant definitions */
#ifndef _FX_SYSTEM_H_
	#include "fx_system.h"
#endif
#ifndef _FX_MEMORY_H_
	#include "fx_memory.h"
#endif
#ifndef _FX_STRING_H_
	#include "fx_string.h"
#endif
#ifndef _FX_STREAM_H_
	#include "fx_stream.h"
#endif
//<<<+++OPENSOURCE_MUST_END

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
#ifndef _FX_EXCEPTION_H_
	#include "fx_exception.h"
#endif
//<<<+++OPENSOURCE_MUST_END
#endif

//*****************************************************************************
//* Buffer
//*****************************************************************************
/**
 * @brief Dynamic binary buffers designed for more efficient appending.
 */
class CFX_BinaryBuf : public CFX_Object
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** A default constructor creating an empty buffer. */
	CFX_BinaryBuf(IFX_Allocator* pAllocator = NULL);
	/** A constructor creating a buffer with specified size. */
	CFX_BinaryBuf(FX_STRSIZE size, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_BinaryBuf();
	CFX_BinaryBuf(FX_STRSIZE size);
	//<<<+++OPENSOURCE_END
#endif
	/** The destructor. */
	~CFX_BinaryBuf();

	/** Set the binary buffer to be empty. */
	void					Clear();
	/**
	 * Change the allocated buffer size, and set the allocation step if alloc_step is non-zero. 
	 * 
	 * @param[in] size			The new size expected.
	 * @param[in] alloc_step	The new allocation step. If alloc_step is 0, then the allocation step will not change.
	*/
	void					EstimateSize(FX_STRSIZE size, FX_STRSIZE alloc_step = 0);

	/**
	 * Append a binary buffer block.
	 *
	 * @param[in] pBuf			A pointer to a binary buffer block.
	 * @param[in] size			The size in bytes of the buffer block.
	 */
	void					AppendBlock(const void* pBuf, FX_STRSIZE size);
	/**
	 * Append a byte for specified number times. Not a byte-by-byte processing, but a byte filling processing internally.
	 * 
	 * @param[in] byte			The input byte.
	 * @param[in] count			Number of times.
	 */
	void					AppendFill(FX_BYTE byte, FX_STRSIZE count);
	/**
	 * Append a non-buffered byte string.
	 *
	 * @param[in] str			A no-buffered byte string.
	 */
	void					AppendString(FX_BSTR str) { AppendBlock(str.GetPtr(), str.GetLength()); }
	/**
	 * Append a single byte.
	 *
	 * @param[in] byte			A single byte.
	 */
	inline void				AppendByte(FX_BYTE byte) 
	{
		if (m_AllocSize <= m_DataSize)
			ExpandBuf(1);
		m_pBuffer[m_DataSize++] = byte;
	}

	/**
	 * Insert a binary buffer block at the specified position.
	 *
	 * @param[in] pos			Specifies the zero-based index of the position in the binary buffer.
	 * @param[in] pBuf			A pointer to a binary buffer block.
	 * @param[in] size			The size in bytes of the buffer block.
	 */
	void					InsertBlock(FX_STRSIZE pos, const void* pBuf, FX_STRSIZE size);

	/**
	 * Attach to a buffer (this buffer will belong to this object). The buffer must be allocated by FX_Alloc.
	 * 
	 *
	 * @param[in] pBuf		A pointer to a binary buffer.
	 * @param[in] size			The size in bytes of the buffer.
	 */
	void					AttachData(void* pBuf, FX_STRSIZE size);
	/**
	 * Copy from another buffer.
	 *
	 * @param[in] pBuf			A pointer to a binary buffer.			
	 * @param[in] size			The size in bytes of the input buffer.
	 */
	void					CopyData(const void* pBuf, FX_STRSIZE size);
	/**
	 * Takeover another buffer. It attaches to the source CFX_BinaryBuf object's buffer; The source CFX_BinaryBuf object
	 * has detached the buffer.
	 *
	 * @param[in] other			A ref to CFX_BinaryBuf object.
	 */
	void					TakeOver(CFX_BinaryBuf& other);

	/**
	 * Delete a inter-zone buffer defining by parameters start_index and count in the binary buffer.
	 *
	 * @param[in] start_index	Specifies the zero-based index of the start position to be deleted in the binary buffer.
	 * @param[in] count			Specifies the length in bytes to be deleted.
	 */
	void					Delete(int start_index, int count);

	/**
	 * Get a byte pointer to the binary buffer.
	 *
	 * @return A byte pointer to the binary buffer.
	 */
	FX_LPBYTE				GetBuffer() const { return m_pBuffer; }
	/**
	 * Get the length of the binary buffer.
	 *
	 * @return The length in bytes of the binary buffer.
	 */
	FX_STRSIZE				GetSize() const { return m_DataSize; }

	/**
	 * Get a byte string from the buffer.
	 *
	 * @return A byte string.
	 */
	CFX_ByteStringC			GetByteString() const;
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	void					GetByteStringL(CFX_ByteStringL &str) const;
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Detach the buffer. Just set buffer pointer to NULL, and set the binary buffer size to zero.
	 */
	void					DetachBuffer();
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Special allocator pointer. NULL to use default allocator. */
	IFX_Allocator*			m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif

protected:
	/** Allocation step. */
	FX_STRSIZE				m_AllocStep;
	/** The buffer pointer. */
	FX_LPBYTE				m_pBuffer;
	/** The length in bytes of the buffer. */
	FX_STRSIZE				m_DataSize;
	/** Allocation size in bytes of the buffer. */
	FX_STRSIZE				m_AllocSize;
	/**
	 * Increase allocated buffer, not data size.
	 *
	 * @param[in] size		The size in bytes to increase.	
	 */
	void					ExpandBuf(FX_STRSIZE size);
};

/**
 * @brief Dynamic byte text buffers designed for more efficient appending.
 */
class CFX_ByteTextBuf : public CFX_BinaryBuf
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* Construct with allocator.
		*
		* @param[in] pAllocator	Allocator used in this class. NULL to use default allocator.
		*/
	CFX_ByteTextBuf(IFX_Allocator* pAllocator = NULL) : CFX_BinaryBuf(pAllocator) {}
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * assignment(=) operator overload. From a non-buffered byte string.
	 *
	 * @param[in] str		A non-buffered byte string.
	 */
	void					operator = (FX_BSTR str);

	/**
	 * Append a single character or byte.
	 *
	 * @param[in] ch		A single character or byte.
	 */
	void					AppendChar(int ch) { AppendByte((FX_BYTE)ch); }

	/**
	 * left shifts(<<) operator overload. Outputs a integer to the byte text buffer.
	 *
	 * @param[in] i			The input integer.
	 * @return A ref to the byte text buffer.
	 */
	CFX_ByteTextBuf&		operator << (int i);
	/**
	 * left shifts(<<) operator overload. Outputs a FX_DWORD to the byte text buffer.
	 *
	 * @param[in] i			The input value of FX_DWORD type.
	 * @return A ref to the byte text buffer.
	 */
	CFX_ByteTextBuf&		operator << (FX_DWORD i);
	/**
	 * left shifts(<<) operator overload. Outputs a double value to the byte text buffer.
	 *
	 * @param[in] f			The input double value.
	 * @return A ref to the byte text buffer.
	 */
	CFX_ByteTextBuf&		operator << (double f);
	/**
	 * left shifts(<<) operator overload. Outputs a non-buffered byte string to the byte text buffer.
	 *
	 * @param[in] lpsz		The input non-buffered byte string.
	 * @return A ref to the byte text buffer.
	 */
	CFX_ByteTextBuf&		operator << (FX_BSTR lpsz);
	/**
	 * left shifts(<<) operator overload. Outputs a byte text buffer to the byte text buffer.
	 *
	 * @param[in] buf		The input byte text buffer.
	 * @return A ref to the byte text buffer.
	 */
	CFX_ByteTextBuf&		operator << (const CFX_ByteTextBuf& buf);

	/**
	 * Get the length of the byte text buffer.
	 *
	 * @return The length of the byte text buffer.
	 */
	FX_STRSIZE				GetLength() const { return m_DataSize; }
};

/**
 * @brief Dynamic wide text buffers designed for more efficient appending.
 */
class CFX_WideTextBuf : public CFX_BinaryBuf
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* Construct with allocator.
		*
		* @param[in] pAllocator	Allocator used in this class. NULL to use default allocator.
		*/
	CFX_WideTextBuf(IFX_Allocator* pAllocator = NULL) : CFX_BinaryBuf(pAllocator) {}
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * assignment(=) operator overload. From a zero terminated wide character string.
	 *
	 * @param[in] lpsz		A zero terminated wide character string.
	 */
	void					operator = (FX_LPCWSTR lpsz);
	/**
	 * assignment(=) operator overload. From a wide string.
	 *
	 * @param[in] str		A wide string.
	 */
	void					operator = (FX_WSTR str);

	/**
	 * Append a single wide character.
	 *
	 * @param[in] wch		A single wide character.
	 */
	void					AppendChar(FX_WCHAR wch);

	/**
	 * left shifts(<<) operator overload. Outputs a integer to the wide text buffer.
	 *
	 * @param[in] i			The input integer.
	 * @return A ref to the wide text buffer.
	 */
	CFX_WideTextBuf&		operator << (int i);
	/**
	 * left shifts(<<) operator overload. Outputs a double value to the wide text buffer.
	 *
	 * @param[in] f			The input double value.
	 * @return A ref to the wide text buffer.
	 */
	CFX_WideTextBuf&		operator << (double f);
	/**
	 * left shifts(<<) operator overload. Outputs a zero-terminated wide character string to the wide text buffer.
	 *
	 * @param[in] lpsz		The input zero-terminated wide character string.
	 * @return A ref to the wide text buffer.
	 */
	CFX_WideTextBuf&		operator << (FX_LPCWSTR lpsz);
	/**
	 * left shifts(<<) operator overload. Outputs a wide string to the wide text buffer.
	 *
	 * @param[in] str		The input wide string.
	 * @return A ref to the wide text buffer.
	 */
	CFX_WideTextBuf&		operator << (FX_WSTR str);
	CFX_WideTextBuf&		operator << (const CFX_WideString &str);
	/**
	 * left shifts(<<) operator overload. Outputs a wide text buffer to the wide text buffer.
	 *
	 * @param[in] buf			The input wide text buffer.
	 * @return A ref to the wide text buffer.
	 */
	CFX_WideTextBuf&		operator << (const CFX_WideTextBuf& buf);

	/**
	 * Get the length of the wide text buffer.
	 *
	 * @return The count of wide characters in the wide text buffer.
	 */
	FX_STRSIZE				GetLength() const { return m_DataSize/sizeof(FX_WCHAR); }
	/**
	 * Get a wide character pointer.
	 *
	 * @return A wide character pointer to the wide text buffer.
	 */
	FX_LPWSTR				GetBuffer() const { return (FX_LPWSTR)m_pBuffer; }

	/**
	 * Delete a inter-zone buffer defining by parameters start_index and count in the wide text buffer.
	 *
	 * @param[in] start_index	Specifies the zero-based index of the start position to be deleted in the wide text buffer buffer.
	 * @param[in] count			Specifies the count of wide characters to be deleted.
	 */
	void					Delete(int start_index, int count) 
	{ CFX_BinaryBuf::Delete(start_index*sizeof(FX_WCHAR), count*sizeof(FX_WCHAR)); }

	/**
	 * Get a wide string from the wide text buffer.
	 *
	 * @return A wide string.
	 */
	CFX_WideStringC			GetWideString() const;
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	void					GetWideStringL(CFX_WideStringL& wideText) const;
	//<<<+++OPENSOURCE_END
#endif
};

//*****************************************************************************
//* Archive
//*****************************************************************************
/**
 * @brief Binary archive using memory based buffer or stream.
 * 
 * Providing cross-platform data serialization and de-serialization service.
 * Data structure is NOT stored in the archive, so the de-serialization must use exactly same
 * structure in when serialization.
 */
class CFX_ArchiveSaver : public CFX_Object
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Construct with allocator.
	 *
	 * @param[in] pAllocator	Allocator used in this class. NULL to use default allocator.
	 */
	CFX_ArchiveSaver(IFX_Allocator* pAllocator = NULL) : m_SavingBuf(pAllocator), m_pStream(NULL) {}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_ArchiveSaver() : m_pStream(NULL) {}
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * left shifts(<<) operator overload. Serializes a single byte.
	 *
	 * @param[in] i		The input byte.
	 * @return A ref to the archive saver.
	 */
	CFX_ArchiveSaver&		operator << (FX_BYTE i);
	/**
	 * left shifts(<<) operator overload. Serializes a integer.
	 *
	 * @param[in] i		The input integer.
	 * @return A ref to the archive saver.
	 */
	CFX_ArchiveSaver&		operator << (int i);
	/**
	 * left shifts(<<) operator overload. Serializes a FX_DWORD value.
	 *
	 * @param[in] i		The input FX_DWORD value.
	 * @return A ref to the archive saver.
	 */
	CFX_ArchiveSaver&		operator << (FX_DWORD i);
	/**
	 * left shifts(<<) operator overload. Serializes a floating-point.
	 *
	 * @param[in] i		The input floating-point.
	 * @return A ref to the archive saver.
	 */
	CFX_ArchiveSaver&		operator << (FX_FLOAT i);
	/**
	 * left shifts(<<) operator overload. Serializes a double value.
	 *
	 * @param[in] i		The input double value.
	 * @return A ref to the archive saver.
	 */
	CFX_ArchiveSaver&		operator << (double i);

	/**
	 * left shifts(<<) operator overload. Serializes a non-buffered byte string.
	 *
	 * @param[in] bstr		The input non-buffered byte string.
	 * @return A ref to the archive saver.
	 */
	CFX_ArchiveSaver&		operator << (FX_BSTR bstr);
	/**
	 * left shifts(<<) operator overload. Serializes a zero-terminated wide character string.
	 *
	 * @param[in] bstr		The input zero-terminated wide character string.
	 * @return A ref to the archive saver.
	 *
	 * @note Wide strings are stored in UTF-16LE encoding.
	 */
	CFX_ArchiveSaver&		operator << (FX_LPCWSTR bstr);
	/**
	 * left shifts(<<) operator overload. Serializes a wide string.
	 *
	 * @param[in] wstr		The input wide string.
	 * @return A ref to the archive saver.
	 *
	 * @note Wide strings are stored in UTF-16LE encoding.
	 */
	CFX_ArchiveSaver&		operator << (const CFX_WideString& wstr);

	/**
	 * Serialize a memory block.
	 *
	 * @param[in] pData		The pointer to a memory block.
	 * @param[in] dwSize	The size in bytes of the memory block.
	 */
	void					Write(const void* pData, FX_STRSIZE dwSize);

	/**
	 * Get the length of saved data.
	 *
	 * @return the length in bytes of the saved data.
	 */
	FX_INTPTR				GetLength() { return m_SavingBuf.GetSize(); }
	/**
	 * Get the constant byte pointer to the saved data.
	 *
	 * @return the constant byte pointer to the saved data. 
	 */
	FX_LPCBYTE				GetBuffer() { return m_SavingBuf.GetBuffer(); }

	/** 
	 * Set the attached stream.
	 *
	 * @param[in] pStream	The stream to the saved data.
	 */
	void					SetStream(IFX_FileStream* pStream) {m_pStream = pStream;}

protected:
	/** Saving data. */
	CFX_BinaryBuf			m_SavingBuf;
	/** Stream data. */
	IFX_FileStream*			m_pStream;
};

/**
 * @brief Archive loader.
 */
class CFX_ArchiveLoader : public CFX_Object
{
public:
	/**
	 * Construct a loading archive.
	 *
	 * @note The source data buffer must be valid during de-serialization.
	 *
	 * @param[in] pData		The source data buffer to be de-serialized.
	 * @param[in] dwSize	The length in bytes of the source data buffer.
	 */
	CFX_ArchiveLoader(FX_LPCBYTE pData, FX_DWORD dwSize);

	/**
	 * right shifts(>>) operator overload. De-serialize a byte.
	 *
	 * @param[out] i		A ref to an byte to receive the byte value.
	 * @return A ref to the archive loader.
	 */
	CFX_ArchiveLoader&		operator >> (FX_BYTE& i);
	/**
	 * right shifts(>>) operator overload. De-serialize a integer.
	 *
	 * @param[out] i		A ref to an integer to receive the integer value.
	 * @return A ref to the archive loader.
	 */
	CFX_ArchiveLoader&		operator >> (int& i);
	/**
	 * right shifts(>>) operator overload. De-serialize a FX_DWORD.
	 *
	 * @param[out] i		A ref to an FX_DWORD to receive the FX_DWORD value.
	 * @return A ref to the archive loader.
	 */
	CFX_ArchiveLoader&		operator >> (FX_DWORD& i);
	/**
	 * right shifts(>>) operator overload. De-serialize a floating-point.
	 *
	 * @param[out] i		A ref to an floating-point to receive the floating-point value.
	 * @return A ref to the archive loader.
	 */
	CFX_ArchiveLoader&		operator >> (FX_FLOAT& i);
	/**
	 * right shifts(>>) operator overload. De-serialize a double.
	 *
	 * @param[out] i		A ref to an double to receive the double value.
	 * @return A ref to the archive loader.
	 */
	CFX_ArchiveLoader&		operator >> (double& i);

	/**
	 * right shifts(>>) operator overload. De-serialize a byte string.
	 *
	 * @param[out] bstr		A ref to an byte string to receive the byte string value.
	 * @return A ref to the archive loader.
	 */
	CFX_ArchiveLoader&		operator >> (CFX_ByteString& bstr);
	/**
	 * right shifts(>>) operator overload. De-serialize a wide string.
	 *
	 * @param[out] wstr		A ref to an wide string to receive the wide string value.
	 * @return A ref to the archive loader.
	 */
	CFX_ArchiveLoader&		operator >> (CFX_WideString& wstr);

	/**
	 * Return whether de-serializing to the end of the loading buffer.
	 *
	 * @return non-zero means de-serializing to the end, otherwise not.
	 */
	FX_BOOL					IsEOF();

	/**
	 * De-serialize a memory block.
	 *
	 * @param[in,out] pBuf	A memory block pointer to receive the data. 
	 * @param[in] dwSize	The size in bytes of the memory block.
	 * @return non-zero means successful, otherwise failed.
	 */
	FX_BOOL					Read(void* pBuf, FX_DWORD dwSize);

protected:
	/** Current loading position. */
	FX_DWORD				m_LoadingPos;
	/** Loading buffer. */
	FX_LPCBYTE				m_pLoadingBuf;
	/** The size in bytes of the loading buffer. */
	FX_DWORD				m_LoadingSize;
};

/**
 * @brief Buffer Archive
 */
class IFX_BufferArchive
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * @brief	Construct with buffer size and special allocator.
	 *
	 * @param[in] size			Initial buffer size.
	 * @param[in] pAllocator	Allocator used in this class. NULL to use default allocator.
	 */
	IFX_BufferArchive(FX_STRSIZE size, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	IFX_BufferArchive(FX_STRSIZE size);
	//<<<+++OPENSOURCE_END
#endif
	
	/**
	 * Clear the text buffer.
	 *
	 */
	virtual void			Clear();
	
	/**
	 * Flush internal buffer of the file.
	 *
	 * @return	TRUE if flushes successfully, or FALSE to indicate error.
	 */
	FX_BOOL					Flush();
	
	/**
	 * Append a binary buffer block.
	 *
	 * @param[in] pBuf		A pointer to a binary buffer block.
	 * @param[in] size		The size in bytes of the buffer block.
	 *
	 * @return				-1 if any error, or buffer size.
	 */
	FX_INT32				AppendBlock(const void* pBuf, size_t size);

	/**
	 * Append a single byte.
	 *
	 * @param[in] byte		A single byte.
	 *
	 * @return				-1 if any error, or buffer size.
	 */
	FX_INT32				AppendByte(FX_BYTE byte);

	/**
	 * Append a FX_DWORD value.
	 *
	 * @param[in] i			A FX_DWORD value.
	 *
	 * @return				-1 if any error, or buffer size.
	 */
	FX_INT32				AppendDWord(FX_DWORD i);
	
	/**
	 * Append a byte string value.
	 *
	 * @param[in] lpsz		A byte string value.
	 *
	 * @return				-1 if any error, or buffer size.
	 */
	FX_INT32				AppendString(FX_BSTR lpsz);
	
protected:
	/**
	 * Do work, it will be called when the text buffer is full.
	 *
	 * @param[in] pBuf		A pointer to a binary buffer block.
	 * @param[in] size		The size in bytes of the buffer block.
	 * @return				Return FALSE for failure.
	 */
	virtual	FX_BOOL			DoWork(const void* pBuf, size_t size) = 0;
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Special allocator pointer. NULL to use default allocator. */
	IFX_Allocator*			m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif
	/** The buffer size*/
	FX_STRSIZE				m_BufSize;
	/** Buffer. */
	FX_LPBYTE				m_pBuffer;
	/** Current buffer length. */
	FX_STRSIZE				m_Length;
};

/**
 * @brief File Buffer Archive
 */
class CFX_FileBufferArchive : public IFX_BufferArchive, public CFX_Object
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CFX_FileBufferArchive(FX_STRSIZE size = 32768, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_FileBufferArchive(FX_STRSIZE size = 32768);
	//<<<+++OPENSOURCE_END
#endif
	~CFX_FileBufferArchive();

	virtual void			Clear();

	/**
	 * Attach file
	 *
	 * @param[in] pFile		A pointer to file stream.
	 * @param[in] bTakeover	Whether take over the file.
	 */
	FX_BOOL					AttachFile(IFX_StreamWrite *pFile, FX_BOOL bTakeover = FALSE);

	/**
	 * Attach file
	 *
	 * @param[in] filename	unicode file name. Available only for platforms supporting CRT file access (fopen, ...).
	 */
	FX_BOOL					AttachFile(FX_LPCWSTR filename);

	/**
	 * Attach file
	 *
	 * @param[in] filename	unicode file name. Available only for platforms supporting CRT file access (fopen, ...).
	 */
	FX_BOOL					AttachFile(FX_LPCSTR filename);

private:
	/**
	 * Do work, it will be called when the text buffer is full.
	 *
	 * @param[in] pBuf		A pointer to a binary buffer block.
	 * @param[in] size		The size in bytes of the buffer block.
	 * @return				Return FALSE for failure.
	 */
	virtual FX_BOOL			DoWork(const void* pBuf, size_t size);

	/** The file stream. */
	IFX_StreamWrite			*m_pFile;
	/** whether take over the file. */
	FX_BOOL					m_bTakeover;
};

/**
 * @brief Abstract class for character mappings (encodings).
 * All character maps should have the ability to convert between internal encoding and Unicode.
 */
struct CFX_CharMap
{
	/**
	 * Get a character mapper according to Windows code page or other encoding system.
	 * This char maps are managed by FXAPI, don't destroy them.
	 *
	 * This is system default mapper according to locale settings.
	 * 
	 * @return A character mapper.
	 */
	static CFX_CharMap*		GetDefaultMapper(FX_INT32 codepage = 0);
	
	/**
	 * A pointer type to GetWideString function.
	 * 
	 * The function converts a byte string to a wide string according a  character mapper.\n
	 * The function prototype is:
	 *		CFX_WideString GetWideString(CFX_CharMap* pMap, const CFX_ByteString& bstr);
	 * @param[in] pMap		A character mapper.
	 * @param[in] bstr		A byte string.
	 * @return A wide string.
	 */
	CFX_WideString	(*m_GetWideString)(CFX_CharMap* pMap, const CFX_ByteString& bstr);
	/**
	 * A pointer type to GetByteString function.
	 * 
	 * The function converts a wide string to a byte string according a  character mapper.\n
	 * The function prototype is:
	 *		CFX_ByteString GetByteString(CFX_CharMap* pMap, const CFX_WideString& wstr);
	 * @param[in] pMap		A character mapper.
	 * @param[in] wstr		A wide string.
	 * @return A byte string.
	 */
	CFX_ByteString	(*m_GetByteString)(CFX_CharMap* pMap, const CFX_WideString& wstr);
	/** 
	 * A pointer type to GetCodePage function. 
	 * 
	 * The function return a code page of the platform.
	 */
	FX_INT32		(*m_GetCodePage)();
};

//*****************************************************************************
//* UTF-8
//*****************************************************************************
/**
 * @brief A simple UTF-8 decoder.
 */
class CFX_UTF8Decoder
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * A constructor. Set the decoder to initial.
	 */
	CFX_UTF8Decoder(IFX_Allocator* pAllocator = NULL) : m_Buffer(pAllocator) { m_PendingBytes = 0; }
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_UTF8Decoder(){ m_PendingBytes = 0; }
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Clear the decoding status and set the output wide text buffer to be empty.
	 */
	void			Clear();

	/**
	 * Input a byte.
	 *
	 * @param[in] byte		The input byte.
	 */
	void			Input(FX_BYTE byte);
	/**
	 * Append characters to wide text buffer.
	 *
	 * @param[in] ch		The input character.
	 */
	void			AppendChar(FX_DWORD ch);

	/**
	 * Clear the decoding status.
	 */
	void			ClearStatus() { m_PendingBytes = 0; }

	/**
	 * Get the result.
	 *
	 * @return A wide string.
	 */
	CFX_WideStringC	GetResult() const { return m_Buffer.GetWideString(); }
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	void			GetResult(CFX_WideStringL &result) const {m_Buffer.GetWideStringL(result);}
	//<<<+++OPENSOURCE_END
#endif

protected:
	/** The decoding status. */
	int				m_PendingBytes;
	/** Cached value. */
	FX_DWORD		m_PendingChar;
	/** The output wide text buffer. */
	CFX_WideTextBuf	m_Buffer;
};

/**
 * @brief A simple UTF-8 encoder.
 */
class CFX_UTF8Encoder
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * A constructor. Set the encoder to initial.
	 */
	CFX_UTF8Encoder(IFX_Allocator* pAllocator = NULL) : m_Buffer(pAllocator) { m_UTF16First = 0; }
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_UTF8Encoder() { m_UTF16First = 0; }
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Input a unicode.
	 *
	 * @param[in] unicode		The input unicode.
	 * 
	 */
	void			Input(FX_WCHAR unicode);

	/**
	 * Append a non-buffered byte string.
	 *
	 * @param[in] str			A non-buffered byte string.
	 */
	void			AppendStr(FX_BSTR str) { m_UTF16First = 0; m_Buffer << str; }

	/**
	 * Get the result.
	 *
	 * @return A byte string.
	 */
	CFX_ByteStringC	GetResult() const { return m_Buffer.GetByteString(); }
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	void			GetResult(CFX_ByteStringL &result) const {m_Buffer.GetByteStringL(result);}
	//<<<+++OPENSOURCE_END
#endif

protected:
	/** The output byte text buffer. */
	CFX_ByteTextBuf	m_Buffer;
	/** The encoding status. */
	FX_DWORD		m_UTF16First;
};

/**
 * @brief A simple URL encode.
 */
CFX_ByteString FX_UrlEncode(const CFX_WideString& wsUrl);

/**
 * @brief A simple URL decode.
 */
CFX_WideString FX_UrlDecode(const CFX_ByteString& bsUrl);

/**
 * @brief A simple URI encode.
 */
CFX_ByteString FX_EncodeURI(const CFX_WideString& wsURI);

/**
 * @brief A simple URI Decode.
 */
CFX_WideString FX_DecodeURI(const CFX_ByteString& bsURI);

//*****************************************************************************
//* Array
//*****************************************************************************
/**
 * @brief Basic array class. Total allocated size is limited to 2^28 bytes (256MB).
 */
class CFX_BasicArray : public CFX_Object
{
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
public:
	/** Special allocator pointer. NULL to use default allocator. */
	IFX_Allocator*	m_pAllocator;
protected:
	/**
		* Construct with specified unit size.
		*
		* @param[in] unit_size		The specified unit size. Must be greater than 0 and less than 2^28.
		* @param[in] pAllocator	Allocator used in this class. NULL to use default allocator.
		*/
	CFX_BasicArray(int unit_size, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
protected:
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_BasicArray(int unit_size);
	//<<<+++OPENSOURCE_END
#endif
	/**
	 * The destructor.
	 */
	~CFX_BasicArray();

	/**
	 * Change the allocated size and the grow amount.
	 *
	 * @param[in] nNewSize		The new size in elements expected.
	 * @param[in] nGrowBy		The grow amount in elements expected, nGrowBy can be -1 for the grow amount unchanged.
	 * @return TRUE for success, FALSE for error (parameter or memory error).
	 */
	FX_BOOL			SetSize(int nNewSize, int nGrowBy);
	/**
	 * Append a basic array.
	 *
	 * @param[in] src			The input basic array. It must have the save unit size as the current array.
	 * @return TRUE for success, FALSE for error (memory error).
	 */
	FX_BOOL			Append(const CFX_BasicArray& src);
	/**
	 * Copy from a basic array.
	 *
	 * @param[in] src			The input basic array. It must have the save unit size as the current array.
	 * @return TRUE for success, FALSE for error (memory error).
	 */
	FX_BOOL			Copy(const CFX_BasicArray& src);
	/**
	 * Insert spaces at specified position.
	 *
	 * @param[in] nIndex		Specifies the zero-based index of element in the basic array.
	 * @param[in] nCount		Specifies the count of element to insert.
	 * @return A byte pointer to the inserted space. NULL for error.
	 */
	FX_LPBYTE		InsertSpaceAt(int nIndex, int nCount);
	/**
	 * Remove a number of elements.
	 * 
	 * @param[in] nIndex		Specifies the zero-based index of start element in the basic array to be removed.
	 * @param[in] nCount		Specifies the count of element to remove.
	 * @return TRUE for success, FALSE for error (parameter error).
	 */
	FX_BOOL			RemoveAt(int nIndex, int nCount);
	/**
	 * Insert a basic array at specified position.
	 *
	 * @param[in] nStartIndex	Specifies the zero-based index of start element to insert at.
	 * @param[in] pNewArray		The input basic array. It must have the save unit size as the current array.
	 * @return TRUE for success, FALSE for error (parameter or memory error).
	 */
	FX_BOOL			InsertAt(int nStartIndex, const CFX_BasicArray* pNewArray);
	/**
	 * Get a typeless pointer to an element data.
	 *
	 * @param[in] index			Specifies the zero-based index of element.
	 * @return A typeless pointer to the element data. NULL for error.
	 */
	const void*		GetDataPtr(int index) const;

protected:
	/** the actual array of data */
	FX_LPBYTE		m_pData;
	/**  # of elements (upperBound - 1) */
	int				m_nSize;
	/** max allocated */
	int				m_nMaxSize;
	/** grow amount. */
	int				m_nGrowBy;
	/** number of bytes in one unit. */
	int				m_nUnitSize;
};

/**
 * @brief Array template. Total allocated size is limited to 2^28 bytes (256MB).
 */
template<class TYPE>
class CFX_ArrayTemplate : public CFX_BasicArray
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* The constructor.
		*/
	CFX_ArrayTemplate(IFX_Allocator* pAllocator = NULL) : CFX_BasicArray(sizeof(TYPE), pAllocator) {}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_ArrayTemplate() : CFX_BasicArray(sizeof(TYPE)) {}
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Get the number of elements in the array.
	 * 
	 * @return The number of elements in the array.
	 */
	int			GetSize() const { return m_nSize; }
	/**
	 * Get the upper bound in the array. actually the maximum valid index.
	 *
	 * @return The upper bound.
	 */
	int			GetUpperBound() const { return m_nSize-1; }
	/**
	 * Change the allocated size and the grow amount.
	 *
	 * @param[in] nNewSize		The new size in elements expected.
	 * @param[in] nGrowBy		The grow amount in elements expected, nGrowBy can be -1 for the grow amount unchanged.
	 * @return TRUE for success, FALSE for error (parameter or memory error).
	 */
	FX_BOOL		SetSize(int nNewSize, int nGrowBy = -1) 
	{
		return CFX_BasicArray::SetSize(nNewSize, nGrowBy); 
	}

	/**
	 * Clean up the array.
	 */
	void		RemoveAll() { SetSize(0, -1); }

	/**
	 * This method retrieves an element specified by an index number.
	 *
	 * @param[in] nIndex	Specifies the zero-based index of the element.
	 * @return An element.
	 */
	const TYPE	GetAt(int nIndex) const
	{
		if (nIndex < 0 || nIndex >= m_nSize) 
			return (const TYPE&)(*(volatile const TYPE*)NULL);
		return ((const TYPE*)m_pData)[nIndex];
	}

	/**
	 * This method overwrites an element specified by an index number.
	 *
	 * @param[in] nIndex		Specifies the zero-based index of the element.
	 * @param[in] newElement	An element.
	 */
	FX_BOOL		SetAt(int nIndex, TYPE newElement) 
	{
		if (nIndex < 0 || nIndex >= m_nSize) return FALSE;
		((TYPE*)m_pData)[nIndex] = newElement; 
		return TRUE;
	}

	/**
	 * This method retrieves a ref to an element specified by an index number. 
	 *
	 * @param[in] nIndex		Specifies the zero-based index of the element.
	 * @return A ref to the specified element.
	 */
	TYPE&		ElementAt(int nIndex) 
	{ 
		if (nIndex < 0 || nIndex >= m_nSize)
			return *(TYPE*)NULL;
		return ((TYPE*)m_pData)[nIndex]; 
	}

	/**
	 * Direct Access to the element data (may return NULL).
	 *
	 * @return A constant element type pointer.
	 */
	const TYPE*	GetData() const { return (const TYPE*)m_pData; }
	/**
	 * Direct Access to the element data (may return NULL).
	 *
	 * @return An element type pointer.
	 */
	TYPE*		GetData() { return (TYPE*)m_pData; }

	/**
	 * Set an element value at specified position. Potentially growing the array.
	 *
	 * @param[in] nIndex		Specifies the zero-based index of element in the array.
	 * @param[in] newElement	The input element.
	 */
	FX_BOOL		SetAtGrow(int nIndex, TYPE newElement) 
	{
		if (nIndex < 0) return FALSE; 
		if (nIndex >= m_nSize)
			if (!SetSize(nIndex+1, -1)) return FALSE;
		((TYPE*)m_pData)[nIndex] = newElement; 
		return TRUE;
	}
	/**
	 * Add an element at the tail. Potentially growing the array.
	 * 
	 * @param[in] newElement	The input element.
	 * @return TRUE for success, FALSE for error (memory error).
	 */
	FX_BOOL		Add(TYPE newElement)
	{
		if (m_nSize < m_nMaxSize)
			m_nSize ++;
		else
			if (!SetSize(m_nSize+1, -1)) return FALSE;
		((TYPE*)m_pData)[m_nSize-1] = newElement; 
		return TRUE;
	}
	/**
	 * Append an array.
	 *
	 * @param[in] src			The input array.
	 * @return TRUE for success, FALSE for error (memory error).
	 */
	FX_BOOL		Append(const CFX_ArrayTemplate& src) { return CFX_BasicArray::Append(src); }
	/**
	 * Copy from an array.
	 *
	 * @param[in] src			The input array.
	 * @return TRUE for success, FALSE for error (memory error).
	 */
	FX_BOOL		Copy(const CFX_ArrayTemplate& src) { return CFX_BasicArray::Copy(src); }

	/**
	 * Get a pointer to the specified element in the array. Direct pointer access.
	 *
	 * @param[in] index Specifies the zero-based index of element in the array.
	 * @return A pointer to the specified element.
	 */
	TYPE*		GetDataPtr(int index) { return (TYPE*)CFX_BasicArray::GetDataPtr(index); }
	/**
	 * Add an element's space.
	 *
	 * @return A pointer to the added space for the new element.
	 */
	TYPE*		AddSpace() { return (TYPE*)CFX_BasicArray::InsertSpaceAt(m_nSize, 1); }
	/**
	 * Insert a number of elements.
	 * 
	 * @param[in] nIndex	Specifies the zero-based index of start element in the array.
	 * @param[in] nCount	Specifies the count of elements to insert.
	 */
	TYPE*		InsertSpaceAt(int nIndex, int nCount) { return (TYPE*)CFX_BasicArray::InsertSpaceAt(nIndex, nCount); }

	/**
	 * Subscript([]) operator overload. It retrieves a element specified by the zero-based index in nIndex.
	 *
	 * @param[in] nIndex	Specifies the zero-based index in the array.
	 * @return An element value.
	 */
	const TYPE	operator[](int nIndex) const
	{ 
		if (nIndex < 0 || nIndex >= m_nSize) 
			//Merge from google trunk r2049, author: Johnson, date:2012.12.07
			*(volatile char*)0 = '\0';
		return ((const TYPE*)m_pData)[nIndex];
	}
	/**
	 * Subscript([]) operator overload. It retrieves a ref to the specified element specified by the zero-based index in nIndex.
	 *
	 * @param[in] nIndex	Specifies the zero-based index in the array.
	 * @return A ref to the specified element.
	 */
	TYPE&		operator[](int nIndex)
	{
		if (nIndex < 0 || nIndex >= m_nSize) 
			//Merge from google trunk r2049, author: Johnson, date:2012.12.07
			*(volatile char*)0 = '\0';
		return ((TYPE*)m_pData)[nIndex]; 
	}

	/**
	 * Inset one or more continuous element at specified position.
	 *
	 * @param[in] nIndex		Specifies the zero-based index in the array.
	 * @param[in] newElement	Specifies the element value to insert.
	 * @param[in] nCount		Specifies the count of the element to insert.
	 * @return TRUE for success, FALSE for error (parameter or memory error).
	 */
	FX_BOOL		InsertAt(int nIndex, TYPE newElement, int nCount = 1) 
	{ 
		if (!InsertSpaceAt(nIndex, nCount)) return FALSE;
		while (nCount--) 
			((TYPE*)m_pData)[nIndex++] = newElement; 
		return TRUE;
	}
	/**
	 * Remove a number of elements at specified position.
	 *
	 * @param[in] nIndex		Specifies the zero-based index in the array.
	 * @param[in] nCount		Specifies the count of element to remove.
	 * @return TRUE for success, FALSE for error (parameter or memory error).
	 */
	FX_BOOL		RemoveAt(int nIndex, int nCount = 1) { return CFX_BasicArray::RemoveAt(nIndex, nCount); }
	/**
	 * Inset an array at specified position.
	 *
	 * @param[in] nStartIndex	Specifies the zero-based index of start element to insert at.
	 * @param[in] pNewArray		The input array.
	 * @return TRUE for success, FALSE for error (parameter or memory error).
	 */
	FX_BOOL		InsertAt(int nStartIndex, const CFX_BasicArray* pNewArray) { return CFX_BasicArray::InsertAt(nStartIndex, pNewArray); }

	/**
	 * Find an element from specified position to last.
	 *
	 * @param[in] data			The input element.
	 * @param[in] iStart		Specifies the zero-based index of start element to find.
	 * @return An index of the found element. It can be -1 for found none.
	 */
	int			Find(TYPE data, int iStart = 0) const
	{
		if (iStart < 0) return -1;
		for (; iStart < (int)m_nSize; iStart ++)
			if (((TYPE*)m_pData)[iStart] == data) return iStart;
		return -1;
	}
};

/** Defines a byte array type */
typedef CFX_ArrayTemplate<FX_BYTE>		CFX_ByteArray;
/** Defines a word array type. */
typedef CFX_ArrayTemplate<FX_WORD>		CFX_WordArray;
/** Defines a double-word array type. */
typedef CFX_ArrayTemplate<FX_DWORD>		CFX_DWordArray;
/** Defines a typeless pointer array type. */
typedef CFX_ArrayTemplate<void*>		CFX_PtrArray;
/** Defines file size array type. */
typedef CFX_ArrayTemplate<FX_FILESIZE>	CFX_FileSizeArray;
/** @brief type definition for float array. */
typedef CFX_ArrayTemplate<FX_FLOAT>		CFX_FloatArray;
/** @brief type definition for INT32 array. */
typedef CFX_ArrayTemplate<FX_INT32>		CFX_Int32Array;

/**
 * @brief Object array template.
 * Each object in the array is "owned" by the array, so when this array is destructed, or an object 
 * is removed from the array, the object(s) will be destructed.
 * 
 * The template parameter \<class T\> must support "placement new".
 * (any class derived from CFX_Object supports placement new).
 */
template <class ObjectClass>
class CFX_ObjectArray : public CFX_BasicArray
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* The constructor.
		*/
	CFX_ObjectArray(IFX_Allocator* pAllocator = NULL) : CFX_BasicArray(sizeof(ObjectClass), pAllocator) {}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_ObjectArray() : CFX_BasicArray(sizeof(ObjectClass)) {}
	//<<<+++OPENSOURCE_END
#endif
	/**
	 * The destructor.
	 */
	~CFX_ObjectArray() { RemoveAll(); }

	/**
	 * Add a copy of an existing object to the array.
	 * To call this function, the template parameter class must support copy constructor.
	 *
	 * @param[in] data		The input object.
	 */
	void			Add(const ObjectClass& data)
	{
		#ifdef _FXM_OPENSOURCE_
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==GOOGLE
			new ((void*)InsertSpaceAt(m_nSize, 1)) ObjectClass(data);
			//<<<+++OPENSOURCE_MUST_END
		#else
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
			#ifndef _FX_NOPLACEMENTNEW_
				new ((void*)InsertSpaceAt(m_nSize, 1)) ObjectClass(data);
			#else
				::new ((void*)InsertSpaceAt(m_nSize, 1)) ObjectClass(data);
			#endif
			//<<<+++OPENSOURCE_MUST_END
		#endif
	}

	/**
	 * Add an empty object to the array.
	 * To call this function, the template parameter class must support default constructor.
	 *
	 * @return A ref to the newly added object.
	 */
	ObjectClass&	Add()
	{
		#ifdef _FXM_OPENSOURCE_
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==GOOGLE
			return *(ObjectClass*) new ((void*)InsertSpaceAt(m_nSize, 1)) ObjectClass();
			//<<<+++OPENSOURCE_MUST_END
		#else
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
			#ifndef _FX_NOPLACEMENTNEW_
				return *(ObjectClass*) new ((void*)InsertSpaceAt(m_nSize, 1)) ObjectClass();
			#else
				return *(ObjectClass*) ::new ((void*)InsertSpaceAt(m_nSize, 1)) ObjectClass();
			#endif
			//<<<+++OPENSOURCE_MUST_END
		#endif
	}

	/**
	 * Add an empty space to the array.
	 * Caller should initialize object at once to make sure object is available.
	 *
	 * @return Pointer to allocated space.
	 */
	void*			AddSpace()
	{
		return InsertSpaceAt(m_nSize, 1);
	}

	/**
	 * Append an array.
	 *
	 * @param[in] src			The source array.
	 * @param[in] nStart		The starting position to be appended in source array.
	 * @param[in] nCount		The total count of source elements to be appended, -1 for all elements from nStart position.
	 * @return	The number of appended elements from source array.
	 */
	FX_INT32		Append(const CFX_ObjectArray& src, FX_INT32 nStart = 0, FX_INT32 nCount = -1)
	{
		if (nCount == 0) return 0;
		FX_INT32 nSize = src.GetSize();
		if (!nSize) return 0;
		FXSYS_assert(nStart > -1 && nStart < nSize);
		if (nCount < 0) nCount = nSize;
		if (nStart + nCount > nSize) nCount = nSize - nStart;
		if (nCount < 1) return 0;
		nSize = m_nSize;
		InsertSpaceAt(m_nSize, nCount);
		ObjectClass* pStartObj = (ObjectClass*)GetDataPtr(nSize);
		nSize = nStart + nCount;
		for (FX_INT32 i = nStart; i < nSize; i ++, pStartObj++)
		{
		#ifdef _FXM_OPENSOURCE_
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==GOOGLE
			new ((void*)pStartObj) ObjectClass(src[i]);
			//<<<+++OPENSOURCE_MUST_END
		#else
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
			#ifndef _FX_NOPLACEMENTNEW_
				new ((void*)pStartObj) ObjectClass(src[i]);
			#else
				::new ((void*)pStartObj) ObjectClass(src[i]);
			#endif
			//<<<+++OPENSOURCE_MUST_END
		#endif
		}
		return nCount;
	}

	/**
	 * Copy from an array.
	 *
	 * @param[in] src			The source array.
	 * @param[in] nStart		The starting position to be copied in source array.
	 * @param[in] nCount		The total count of source elements to be copied, -1 for all elements from nStart position.
	 * @return	The number of copied elements from source array.
	 */
	FX_INT32		Copy(const CFX_ObjectArray& src, FX_INT32 nStart = 0, FX_INT32 nCount = -1)
	{
		if (nCount == 0) return 0;
		FX_INT32 nSize = src.GetSize();
		if (!nSize) return 0;
		FXSYS_assert(nStart > -1 && nStart < nSize);
		if (nCount < 0) nCount = nSize;
		if (nStart + nCount > nSize) nCount = nSize - nStart;
		if (nCount < 1) return 0;
		RemoveAll();
		SetSize(nCount, -1);
		ObjectClass* pStartObj = (ObjectClass*)m_pData;
		nSize = nStart + nCount;
		for (FX_INT32 i = nStart; i < nSize; i ++, pStartObj++)
		{
		#ifdef _FXM_OPENSOURCE_
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==GOOGLE
			new ((void*)pStartObj) ObjectClass(src[i]);
			//<<<+++OPENSOURCE_MUST_END
		#else
			//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
			#ifndef _FX_NOPLACEMENTNEW_
				new ((void*)pStartObj) ObjectClass(src[i]);
			#else
				::new ((void*)pStartObj) ObjectClass(src[i]);
			#endif
			//<<<+++OPENSOURCE_MUST_END
		#endif
		}
		return nCount;
	}

	/**
	 * Get the size of the array.
	 *
	 * @return The size in objects in the array.
	 */
	int				GetSize() const {return m_nSize;}
	/**
	 * Subscript([]) operator overload. It retrieves a ref to the specified object specified by the zero-based index in nIndex.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A ref to the specified object.
	 */
	ObjectClass&	operator[] (int index) const 
	{ 
		FXSYS_assert(index < m_nSize); 
		return *(ObjectClass*)CFX_BasicArray::GetDataPtr(index); 
	}
	/**
	 * Get a pointer to the specified element in the array. Direct pointer access.
	 *
	 * @param[in] index Specifies the zero-based index of element in the array.
	 * @return A pointer to the specified element.
	 */
	ObjectClass*	GetDataPtr(int index) {return (ObjectClass*)CFX_BasicArray::GetDataPtr(index);}

	/**
	 * Remove an object at specified position.
	 *
	 * @param[in] index		Specifies the zero-based index of object in the array.
	 */
	void			RemoveAt(int index)
	{
		FXSYS_assert(index < m_nSize);
		((ObjectClass*)GetDataPtr(index))->~ObjectClass();
		CFX_BasicArray::RemoveAt(index, 1);
	}

	/**
	 * Remove all objects in the array.
	 */
	void			RemoveAll() 
	{
		for (int i = 0; i < m_nSize; i ++) 
			((ObjectClass*)GetDataPtr(i))->~ObjectClass();
		CFX_BasicArray::SetSize(0, -1);
	}
};

/** Defines a CFX_ByteString array type. */
typedef CFX_ObjectArray<CFX_ByteString> CFX_ByteStringArray;
/** Defines a CFX_WideString array type. */
typedef CFX_ObjectArray<CFX_WideString> CFX_WideStringArray;

/**
 * @brief Grow-able array with allocation in segments.
 */
class CFX_BaseSegmentedArray : public CFX_Object
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* Construct with specified unit size, segment units, and number of index levels.
		*
		* @param[in] unit_size			The specified unit size.
		* @param[in] segment_units		The count of units in each segment, must be less than 32768.
		* @param[in] index_size		The number of segments(index levels) in the array, it must be larger than 1 and less than 256.
		* @param[in] pAllocator		Allocator used in this class. NULL to use default allocator.
		*/
	CFX_BaseSegmentedArray(int unit_size = 1, int segment_units = 512, int index_size = 8, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_BaseSegmentedArray(int unit_size = 1, int segment_units = 512, int index_size = 8);
	//<<<+++OPENSOURCE_END
#endif
	/**
	 * The destructor.
	 */
	~CFX_BaseSegmentedArray();

	/**
	 * Change the unit size and the segment units. This can only be called when array is empty.
	 *
	 * @param[in] unit_size			The new unit size.
	 * @param[in] segment_units		The new count of units in each segment.
	 * @param[in] index_size		The new number of index levels.
	 */
	void	SetUnitSize(int unit_size, int segment_units, int index_size = 8);

	/**
	 * Add an element.
	 *
	 * @return The typeless pointer to the added element.
	 */
	void*	Add();
	/**
	 * Get a typeless pointer to an element data.
	 *
	 * @param[in] index			Specifies the zero-based index of element.
	 * @return A typeless pointer to the element data.
	 */
	void*	GetAt(int index) const;
	/**
	 * Remove all elements in the array.
	 */
	void	RemoveAll();
	/**
	 * Delete a number of elements.
	 * 
	 * @param[in] index		Specifies the zero-based index of start element in the array to be deleted.
	 * @param[in] count		Specifies the count of element to delete.
	 */
	void	Delete(int index, int count = 1);
	/**
	 * Get number of elements in the array.
	 *
	 * @return The number of elements in the array.
	 */
	int		GetSize() const { return m_DataSize; }

	/**
	 * Get number of elements in each segment.
	 *
	 * @return The number of elements in each segment.
	 */
	int		GetSegmentSize() const { return m_SegmentSize; }

	/**
	 * Get number of bytes for each element.
	 *
	 * @return The number of bytes for each element.
	 */
	int		GetUnitSize() const { return m_UnitSize; }

	/**
	* Iterate all units, with a callback function for each unit
	 * @return The current unit when stopped, or NULL when all units iterated.
	*/
	void*	Iterate(FX_BOOL (*callback)(void* param, void* pData), void* param) const;
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Special allocator pointer. NULL to use default allocator. */
	IFX_Allocator*	m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif

private:
	/** Unit size */
	int				m_UnitSize;
	/** Count of units in each segment. */
	short			m_SegmentSize;
	/** Number of index level in the array. */
	FX_BYTE			m_IndexSize;
	/** The current level in the index tree. */
	FX_BYTE			m_IndexDepth;
	/** The current number of units in the array. */
	int				m_DataSize;
	/** index to segments or indices, or directly pointing to the segment if only one segment. */
	void*			m_pIndex;

	void**	GetIndex(int seg_index) const;
	void*	IterateIndex(int level, int& start, void** pIndex, FX_BOOL (*callback)(void* param, void* pData), void* param) const;
	void*	IterateSegment(FX_LPCBYTE pSegment, int count, FX_BOOL (*callback)(void* param, void* pData), void* param) const;
};

/**
 * @brief Grow-able array template with allocation in segments.
 */
template <class ElementType>
class CFX_SegmentedArray : public CFX_BaseSegmentedArray
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* Construct with specified segment units.
		*
		* @param[in] segment_units		The count of units in each segment.
		* @param[in] index_size		The number of segments in the array.
		*/
	CFX_SegmentedArray(int segment_units, int index_size = 8, IFX_Allocator* pAllocator = NULL)
		: CFX_BaseSegmentedArray(sizeof(ElementType), segment_units, index_size, pAllocator)
	{}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_SegmentedArray(int segment_units, int index_size = 8)
		: CFX_BaseSegmentedArray(sizeof(ElementType), segment_units, index_size)
	{}
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Add an element.
	 *
	 * @param[in] data				The input element.
	 */
	void	Add(ElementType data)
	{
		*(ElementType*)CFX_BaseSegmentedArray::Add() = data;
	}

	/**
	 * Subscript([]) operator overload. It retrieves a ref to the specified element specified by the zero-based index.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A ref to the specified element.
	 */
	ElementType& operator [] (int index)
	{
		return *(ElementType*)CFX_BaseSegmentedArray::GetAt(index);
	}
};

/**
	* @brief Fixed buffer but can be bigger if needed
	*/
template <class DataType, int FixedSize>
class CFX_FixedBufGrow : public CFX_Object
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CFX_FixedBufGrow(IFX_Allocator* pAllocator = NULL)
		: m_pAllocator(pAllocator)
		, m_pData(NULL)
	{}
	CFX_FixedBufGrow(int data_size, IFX_Allocator* pAllocator = NULL) 
		: m_pAllocator(pAllocator)
		, m_pData(NULL)
	{
		if (data_size > FixedSize) 
			m_pData = FX_Allocator_Alloc(m_pAllocator, DataType, data_size);
		else
			FXSYS_memset32(m_Data, 0, sizeof(DataType)*FixedSize);
	}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_FixedBufGrow() : m_pData(NULL)
	{}
	CFX_FixedBufGrow(int data_size) : m_pData(NULL)
	{
		if (data_size > FixedSize)
			m_pData = FX_Alloc(DataType, data_size);
		else
			FXSYS_memset32(m_Data, 0, sizeof(DataType)*FixedSize);
	}
	//<<<+++OPENSOURCE_END
#endif
	void SetDataSize(int data_size) {
#ifndef _FXM_OPENSOURCE_
		//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
		if (m_pData)
			FX_Allocator_Free(m_pAllocator, m_pData);
		m_pData = NULL;
		if (data_size > FixedSize) 
			m_pData = FX_Allocator_Alloc(m_pAllocator, DataType, data_size);
		else {
		//<<<+++OPENSOURCE_END
#else
		//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
		if (m_pData)
			FX_Free(m_pData);
		m_pData = NULL;
		if (data_size > FixedSize)
			m_pData = FX_Alloc(DataType, data_size);
		else {
			//<<<+++OPENSOURCE_END
#endif
			FXSYS_memset32(m_Data, 0, sizeof(DataType)*FixedSize);
		}
	}
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	~CFX_FixedBufGrow() { if (m_pData) FX_Allocator_Free(m_pAllocator, m_pData); }
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	~CFX_FixedBufGrow() { if (m_pData) FX_Free(m_pData); }
	//<<<+++OPENSOURCE_END
#endif
	operator DataType*() { return m_pData ? m_pData : m_Data; }

private:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	IFX_Allocator*	m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif
	DataType		m_Data[FixedSize];
	DataType*		m_pData;
};

/**
	* @brief A temporarily allocated buffer
	*/
template <class DataType>
class CFX_TempBuf
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CFX_TempBuf(int size, IFX_Allocator* pAllocator = NULL) : m_pAllocator(pAllocator)
	{ m_pData = FX_Allocator_Alloc(m_pAllocator, DataType, size); }
	~CFX_TempBuf()
	{ if (m_pData) FX_Allocator_Free(m_pAllocator, m_pData); }
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_TempBuf(int size)
	{ m_pData = FX_Alloc(DataType, size); }
	~CFX_TempBuf() 
	{ if (m_pData) FX_Free(m_pData); }
	//<<<+++OPENSOURCE_END
#endif

	DataType&	operator[](int i) { FXSYS_assert(m_pData != NULL); return m_pData[i]; }
	operator DataType*() { return m_pData; }

private:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	IFX_Allocator*	m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif
	DataType*		m_pData;
};

//*****************************************************************************
//* Map
//*****************************************************************************
/**
 * @brief POINTER/DWORD TO POINTER/DWORD MAP.
 */
class CFX_MapPtrToPtr : public CFX_Object
{
protected:
	/**
	 * @brief Association in CFX_MapPtrToPtr.
	 */
	struct CAssoc
	{
		/** Pointer to next association. */
		CAssoc* pNext;

		/** Key data. */
		void* key;
		/** Value data. */
		void* value;
	};

public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* Construct with specified block size.
		*
		* @param[in] nBlockSize		The internal block.
		* @param[in] pAllocator		Allocator used in this class. NULL to use default allocator.
		*/
	CFX_MapPtrToPtr(int nBlockSize = 10, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_MapPtrToPtr(int nBlockSize = 10);
	//<<<+++OPENSOURCE_END
#endif
	/**
	 * The Destructor.
	 */
	~CFX_MapPtrToPtr();

	/**
	 * Get the number of elements.
	 *
	 * @return The number of elements in the map.
	 */
	int GetCount() const { return m_nCount; }
	/**
	 * Is the map empty ?
	 *
	 * @return Non-zero means empty, otherwise not empty.
	 */
	FX_BOOL IsEmpty() const { return m_nCount == 0; }

	/**
	 * Lookup by a key.
	 *
	 * @param[in] key			The key to lookup.
	 * @param[out] rValue		A ref of a typeless pointer to receive the found value.
	 * @return Non-zero means found one, otherwise found none.
	 */
	FX_BOOL Lookup(void* key, void*& rValue) const;
	/**
	 * Retrieve a value pointer by a key.
	 *
	 * @param[in] key			The key to retrieve.
	 * @return A value. NULL if the key is not found.
	 */
	void* GetValueAt(void* key) const;

	/**
	 * Subscript([]) operator overload. Lookup and add if not there.
	 *
	 * @param[in] key			The key to lookup.
	 * @return A ref to the found value.
	 */
	void*& operator[](void* key);

	/**
	 * Add a new (key, value) pair. Add if not exist, otherwise modify.
	 * 
	 * @param[in] key			The key to specify a position.
	 * @param[in] newValue		The new value.
	 */
	void SetAt(void* key, void* newValue) { (*this)[key] = newValue; }

	/**
	 * Removing existing (key, ?) pair.
	 *
	 * @param[in] key			The key to remove.
	 * @return Non-zero means removed one, otherwise It means the key does not exist.
	 */
	FX_BOOL RemoveKey(void* key);
	/**
	 * Remove all the (key, value) pairs in the map.
	 */
	void RemoveAll();

	/**
	 * Get the first key-value pair position. iterating all (key, value) pairs.
	 *
	 * @return The first key-value pair position in the map.
	 */
	FX_POSITION GetStartPosition() const { return (m_nCount == 0) ? NULL : (FX_POSITION)-1; }
	/**
	 * Get the current association and set the position to next association.
	 *
	 * @param[in, out] rNextPosition	Input a position, and receive the next association position.
	 * @param[out] rKey					Receive a key.
	 * @param[out] rValue				Receive a value.
	 */
	void GetNextAssoc(FX_POSITION& rNextPosition, void*& rKey, void*& rValue) const;

	/**
	 * Get the internal hash table size. Advanced features for derived classes.
	 *
	 * @return the hash table size.
	 */
	FX_DWORD GetHashTableSize() const { return m_nHashTableSize; }
	/**
	 * Initialize the hash table.
	 *
	 * @param[in] hashSize				Initialize the hash table size.
	 * @param[in] bAllocNow				Does it Now allocate the hash table? No-zero means yes, otherwise no.
	 */
	void InitHashTable(FX_DWORD hashSize, FX_BOOL bAllocNow = TRUE);

protected:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Special allocator pointer. NULL to use default allocator. */
	IFX_Allocator*	m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif
	/** The hash table. */
	CAssoc** m_pHashTable;
	/** The size of hash table. */
	FX_DWORD m_nHashTableSize;
	/** The number of key-value pair in the map. */
	int m_nCount;
	/** The freed association list internal. */
	CAssoc* m_pFreeList;
	/** The block list internal. */
	struct CFX_Plex* m_pBlocks;
	/** The size in associations of each block. */
	int m_nBlockSize;

	/**
	 * Routine used to user-provided hash keys.
	 *
	 * @note Overwrite-able: special non-virtual (see map implementation for details).
	 *
	 * @param[in] key		The key used to produce hash key.
	 * @return A hash value.
	 */
	FX_DWORD HashKey(void* key) const;

	/**
	 * Allocate a new association.
	 *
	 * @return The pointer to the new allocated association.
	 */
	CAssoc* NewAssoc();
	/**
	 * Free an association.
	 *
	 * @param[in] pAssoc	A pointer to an association.
	 */
	void FreeAssoc(CAssoc* pAssoc);
	/**
	 * Retrieve an association by a key.
	 *
	 * @param[in] key		The input key.
	 * @param[out] hash		The hash value computed.
	 * @return an association.
	 */
	CAssoc* GetAssocAt(void* key, FX_DWORD& hash) const;
};

/**
 * @brief POINTER/DWORD TO POINTER/DWORD MAP template.
 */
template <class KeyType, class ValueType>
class CFX_MapPtrTemplate : public CFX_MapPtrToPtr
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Default constructor. */
	CFX_MapPtrTemplate(IFX_Allocator* pAllocator = NULL) : CFX_MapPtrToPtr(10, pAllocator) {}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_MapPtrTemplate() : CFX_MapPtrToPtr(10) {}
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Lookup by a key.
	 *
	 * @param[in] key			The key to lookup.
	 * @param[out] rValue		A ref of a value to receive the found value.
	 * @return Non-zero means found one, otherwise found none.
	 */
	FX_BOOL	Lookup(KeyType key, ValueType& rValue) const
	{
		FX_LPVOID pValue = NULL;
		if (!CFX_MapPtrToPtr::Lookup((void*)(FX_UINTPTR)key, pValue))
			return FALSE;
		rValue = (ValueType)(FX_UINTPTR)pValue;
		return TRUE;
	}
	/**
	 * Subscript([]) operator overload. Lookup and add if not there.
	 *
	 * @param[in] key			The key to lookup.
	 * @return A ref to the found value.
	 */
	ValueType& operator[](KeyType key) { return (ValueType&)CFX_MapPtrToPtr::operator []((void*)(FX_UINTPTR)key); }
	/**
	 * Add a new (key, value) pair. Add if not exist, otherwise modify.
	 * 
	 * @param[in] key			The key to specify a position.
	 * @param[in] newValue		The new value.
	 */
	void SetAt(KeyType key, ValueType newValue) { CFX_MapPtrToPtr::SetAt((void*)(FX_UINTPTR)key, (void*)(FX_UINTPTR)newValue); }
	/**
	 * Removing existing (key, ?) pair.
	 *
	 * @param[in] key			The key to remove.
	 * @return Non-zero means removed one, otherwise It means the key does not exist.
	 */
	FX_BOOL	RemoveKey(KeyType key) { return CFX_MapPtrToPtr::RemoveKey((void*)(FX_UINTPTR)key); }
	/**
	 * Get the current association and set the position to next association.
	 *
	 * @param[in, out] rNextPosition	Input a position, and receive the next association position.
	 * @param[out] rKey					Receive a key.
	 * @param[out] rValue				Receive a value.
	 */
	void GetNextAssoc(FX_POSITION& rNextPosition, KeyType& rKey, ValueType& rValue) const
	{ 
		void* pKey = NULL; void* pValue = NULL;
		CFX_MapPtrToPtr::GetNextAssoc(rNextPosition, pKey, pValue);
		rKey = (KeyType)(FX_UINTPTR)pKey; rValue = (ValueType)(FX_UINTPTR)pValue;
	}
};

/**
 * @brief A compact map class that simply put all mapping into one single buffer
 * The map is kept sorted so lookup can be pretty fast.
 */
class CFX_CMapDWordToDWord : public CFX_Object
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Constructor with allocator. */
	CFX_CMapDWordToDWord(IFX_Allocator* pAllocator = NULL) : m_Buffer(pAllocator) {}
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Lookup by a key.
	 *
	 * @param[in] key			The key to lookup.
	 * @param[out] value		A ref of a FX_DWORD value to receive the found value.
	 * @return Non-zero means found one, otherwise found none.
	 */
	FX_BOOL			Lookup(FX_DWORD key, FX_DWORD& value) const;

	/**
	 * Add a new (key, value) pair. Add if not exist, otherwise modify.
	 * 
	 * @param[in] key			The key to specify a position.
	 * @param[in] value			The new FX_DWORD value.
	 */
	void			SetAt(FX_DWORD key, FX_DWORD value);

	/**
	 * Change internal allocation size and grow amount.
	 *
	 * @param[in] size			The new allocation size.
	 * @param[in] grow_by		The new grow amount.
	 */
	void			EstimateSize(FX_DWORD size, FX_DWORD grow_by);

	/**
	 * Get the first key-value pair position. iterating all (key, value) pairs.
	 *
	 * @return The first key-value pair position in the map.
	 */
	FX_POSITION		GetStartPosition() const;
	/**
	 * Get the next association.
	 *
	 * @param[in, out] pos		Input a position, and receive the next (key, value) pair position.
	 * @param[out] key			Receive a key.
	 * @param[out] value		Receive a value.
	 */
	void			GetNextAssoc(FX_POSITION& pos, FX_DWORD& key, FX_DWORD& value) const;

protected:
	/** (key, value) pair buffer. */
	CFX_BinaryBuf	m_Buffer;
};

/**
 * @brief BYTE STRING MAP.
 */
class CFX_MapByteStringToPtr : public CFX_Object
{
protected:
	/**
	 * @brief Association in CFX_MapByteStringToPtr.
	 */
	struct CAssoc
	{
		/** Pointer to next association. */
		CAssoc* pNext;

		/** Cached hash value, needed for efficient iteration. */
		FX_DWORD nHashValue;
		/** Key data. */
		CFX_ByteString key;
		/** Value data. */
		void* value;
	};

public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* Construct with specified block size.
		*
		* @param[in] nBlockSize		The internal block.
		* @param[in] pAllocator		Allocator used in this class. NULL to use default allocator.
		*/
	CFX_MapByteStringToPtr(int nBlockSize = 10, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_MapByteStringToPtr(int nBlockSize = 10);
	//<<<+++OPENSOURCE_END
#endif
	/**
	 * Get the number of elements.
	 *
	 * @return The number of elements in the map.
	 */
	int GetCount() const { return m_nCount; }
	/**
	 * Is the map empty ?
	 *
	 * @return Non-zero means empty, otherwise not empty.
	 */
	FX_BOOL IsEmpty() const { return m_nCount == 0; }

	/**
	 * Lookup by a key.
	 *
	 * @param[in] key			The key to lookup.
	 * @param[out] rValue		A ref of a typeless pointer to receive the found value.
	 * @return Non-zero means found one, otherwise found none.
	 */
	FX_BOOL Lookup(FX_BSTR key, void*& rValue) const;

	/**
	 * Subscript([]) operator overload. Lookup and add if not there.
	 *
	 * @param[in] key			The key to lookup.
	 * @return A ref to the found value.
	 */
	void*& operator[](FX_BSTR key);

	/**
	 * Add a new (key, value) pair. Add if not exist, otherwise modify.
	 * 
	 * @param[in] key			The key to specify a position.
	 * @param[in] newValue		The new value.
	 */
	void SetAt(FX_BSTR key, void* newValue) { (*this)[key] = newValue; }

	/**
	 * Removing existing (key, ?) pair.
	 *
	 * @param[in] key			The key to remove.
	 * @return Non-zero means removed one, otherwise It means the key does not exist.
	 */
	FX_BOOL RemoveKey(FX_BSTR key);
	/**
	 * Remove all the (key, value) pairs in the map.
	 */
	void RemoveAll();

	/**
	 * Get the first key-value pair position. iterating all (key, value) pairs.
	 *
	 * @return The first key-value pair position in the map.
	 */
	FX_POSITION GetStartPosition() const { return (m_nCount == 0) ? NULL : (FX_POSITION)-1; }
	/**
	 * Get the current association and set the position to next association.
	 *
	 * @param[in, out] rNextPosition	Input a position, and receive the next association position.
	 * @param[out] rKey					Receive a key.
	 * @param[out] rValue				Receive a value.
	 */
	void GetNextAssoc(FX_POSITION& rNextPosition, CFX_ByteString& rKey, void*& rValue) const;

	/**
	 * Get the the current value and set the position to next association.
	 *
	 * @param[in, out] rNextPosition	Input a position, and receive the next association position.
	 * @return Return a value.
	 */
	FX_LPVOID		GetNextValue(FX_POSITION& rNextPosition) const;

	/**
	 * Get the internal hash table size. Advanced features for derived classes.
	 *
	 * @return the hash table size.
	 */
	FX_DWORD GetHashTableSize() const { return m_nHashTableSize; }
	/**
	 * Initialize the hash table.
	 *
	 * @param[in] hashSize				Initialize the hash table size.
	 * @param[in] bAllocNow				Does it Now allocate the hash table? No-zero means yes, otherwise no.
	 */
	void InitHashTable(FX_DWORD hashSize, FX_BOOL bAllocNow = TRUE);

	/**
	 * Routine used to user-provided hash keys.
	 *
	 * @note Overwrite-able: special non-virtual (see map implementation for details).
	 *
	 * @param[in] key		The key used to produce hash key.
	 * @return A hash value.
	 */
	FX_DWORD HashKey(FX_BSTR key) const;

protected:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Special allocator pointer. NULL to use default allocator. */
	IFX_Allocator*	m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif
	/** The hash table. */
	CAssoc** m_pHashTable;
	/** The size of hash table. */
	FX_DWORD m_nHashTableSize;
	/** The number of key-value pair in the map. */
	int m_nCount;
	/** The freed association list internal. */
	CAssoc* m_pFreeList;
	/** The block list internal. */
	struct CFX_Plex* m_pBlocks;
	/** The size in associations of each block. */
	int m_nBlockSize;

	/**
	 * Allocate a new association.
	 *
	 * @return The pointer to the new allocated association.
	 */
	CAssoc* NewAssoc();
	/**
	 * Free an association.
	 *
	 * @param[in] pAssoc	A pointer to an association.
	 */
	void FreeAssoc(CAssoc* pAssoc);
	/**
	 * Retrieve an association by a key.
	 *
	 * @param[in] key		The input key.
	 * @param[out] hash		The hash value computed.
	 * @return an association.
	 */
	CAssoc* GetAssocAt(FX_BSTR key, FX_DWORD& hash) const;

public:
	/** The destructor. */
	~CFX_MapByteStringToPtr();
};

/**
 * @brief A compact mapping from byte strings to pointers.
 *
 * Use this class instead of CFX_MapByteStringToPtr when:
 * - The number of mappings is mostly limited, for example, tens of mappings;
 * - The length of mapping keys is mostly limited, for example, often less than 8 characters.
 */
class CFX_CMapByteStringToPtr : public CFX_Object
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** The constructor. */
	CFX_CMapByteStringToPtr(IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_CMapByteStringToPtr();
	//<<<+++OPENSOURCE_END
#endif
	/** The destructor. */
	~CFX_CMapByteStringToPtr();

	/**
	 * Remove all key-value pairs in the map.
	 */
	void			RemoveAll();
	/**
	 * Get the first key-value pair position. iterating all (key, value) pairs.
	 *
	 * @return The first key-value pair position in the map.
	 */
	FX_POSITION		GetStartPosition() const;
	/**
	 * Get the current association and set the position to next association.
	 *
	 * @param[in, out] rNextPosition	Input a position, and receive the next association position.
	 * @param[out] rKey					Receive a key.
	 * @param[out] rValue				Receive a value.
	 */
	void			GetNextAssoc(FX_POSITION& rNextPosition, CFX_ByteString& rKey, void*& rValue) const;
	/**
	 * Get the the current value and set the position to next association.
	 *
	 * @param[in, out] rNextPosition	Input a position, and receive the next association position.
	 * @return Return a value.
	 */
	FX_LPVOID		GetNextValue(FX_POSITION& rNextPosition) const;
	/**
	 * Lookup by a key.
	 *
	 * @param[in] key			The key to lookup.
	 * @param[out] rValue		A ref of a typeless pointer to receive the found value.
	 * @return Non-zero means found one, otherwise found none.
	 */
	FX_BOOL			Lookup(FX_BSTR key, void*& rValue) const;
	/**
	 * Add a new (key, value) pair. Add if not exist, otherwise modify.
	 * 
	 * @param[in] key			The key to specify a position.
	 * @param[in] value			The new value.
	 */
	void			SetAt(FX_BSTR key, void* value);
	/**
	 * Removing existing (key, ?) pair.
	 *
	 * @param[in] key			The key to remove.
	 */
	void			RemoveKey(FX_BSTR key);
	/**
	 * Get the number of key-value pairs.
	 *
	 * @return The number of key-value pairs in the map.
	 */
	int				GetCount() const;

	/** Add a key-value pair to the dictionary, assuming there is no duplicated key existing.
	*	This is a function for quickly building up the whole dictionary, but should be used
	*	with care. If duplicate key happens, only the first value will prevail.
	*/
	void			AddValue(FX_BSTR key, void* pValue);

private:
	/** A chained buffer storing keys and values. */
	CFX_BaseSegmentedArray			m_Buffer;
};

//////////////////////////////////////////////////////////////////////
//							Lists
//////////////////////////////////////////////////////////////////////

/**
 * @brief LIST CLASS
 */
class CFX_PtrList : public CFX_Object
{
protected:
	/** @brief Bidirectional node in CFX_PtrList. */
	struct CNode
	{
		/** Pointer to next node. */
		CNode* pNext;
		/** Pointer to previous node. */
		CNode* pPrev;
		/** Node data. */
		void* data;
	};

public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
		* Construct with block size and allocator.
		*/
	CFX_PtrList(int nBlockSize = 10, IFX_Allocator* pAllocator = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_PtrList(int nBlockSize = 10);
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Get the header position.
	 *
	 * @return The header position.
	 */
	FX_POSITION GetHeadPosition() const { return (FX_POSITION)m_pNodeHead; }
	/**
	 * Get the tail position.
	 *
	 * @return The tail position.
	 */
	FX_POSITION GetTailPosition() const { return (FX_POSITION)m_pNodeTail; }

	/**
	 * Get the the current value and set the position to next node.
	 *
	 * @param[in, out] rPosition	Input a position, and receive the next node position.
	 * @return Return a value.
	 */
	void*	GetNext(FX_POSITION& rPosition) const 
	{ CNode* pNode = (CNode*) rPosition; rPosition = (FX_POSITION) pNode->pNext; return pNode->data; }
	/**
	 * Get the the current value and set the position to previous node.
	 *
	 * @param[in, out] rPosition	Input a position, and receive the previous node position.
	 * @return Return a value.
	 */
	void*	GetPrev(FX_POSITION& rPosition) const
	{ CNode* pNode = (CNode*) rPosition; rPosition = (FX_POSITION) pNode->pPrev; return pNode->data; }

	/**
	 * Get the next position.
	 *
	 * @return The next position.
	 */
	FX_POSITION	GetNextPosition(FX_POSITION pos) const { return ((CNode*)pos)->pNext; }
	/**
	 * Get the previous position.
	 *
	 * @return The previous position.
	 */
	FX_POSITION	GetPrevPosition(FX_POSITION pos) const { return ((CNode*)pos)->pPrev; }

	/**
	 * Get an value at specified position.
	 *
	 * @param[in] rPosition			The input position.
	 * @return a value.
	 */
	void*	GetAt(FX_POSITION rPosition) const
	{ CNode* pNode = (CNode*) rPosition; return pNode->data; }

	/**
	 * Get the number of nodes.
	 *
	 * @return The number of nodes in the list.
	 */
	int		GetCount() const { return m_nCount; }

	/**
	 *  Add a value to the tail.
	 *
	 * @param[in] newElement			The value to be added to tail.
	 * @return The new tail position.
	 */
	FX_POSITION	AddTail(void* newElement);
	/**
	 * Add a value to the head.
	 *
	 * @param[in] newElement			The value to be added to head.
	 * @return The new head position.
	 */
	FX_POSITION AddHead(void* newElement);

	/**
	 * Change the value at specified position.
	 * 
	 * @param[in] pos			The position to change.
	 * @param[in] newElement	The new value.
	 */
	void	SetAt(FX_POSITION pos, void* newElement)
	{ CNode* pNode = (CNode*) pos; pNode->data = newElement; }

	/**
	 * Insert a value after specified position.
	 *
	 * @param[in] pos			Specify the position.
	 * @param[in] newElement	The new value.
	 */
	FX_POSITION InsertAfter(FX_POSITION pos, void* newElement);

	/**
	 * Find a value starting after specified position.
	 *
	 * @param[in] searchValue	The value to be searched.
	 * @param[in] startAfter	The position to start after.
	 * @return The found position. NULL if found none.
	 */
	FX_POSITION Find(void* searchValue, FX_POSITION startAfter = NULL ) const;
	/**
	 * Find a value by index number.
	 *
	 * @param[in] index			The zero-based index number of the element.
	 * @return					The found position of the element.
	 */
	FX_POSITION FindIndex(int index) const;

	/**
	 * Remove a node at specified position.
	 *
	 * @param[in] pos			The position to remove.
	 */
	void	RemoveAt(FX_POSITION pos);
	/**
	 * Remove all nodes in the list.
	 */
	void	RemoveAll();

protected:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Special allocator pointer. NULL to use default allocator. */
	IFX_Allocator*	m_pAllocator;
	//<<<+++OPENSOURCE_END
#endif
	/** Pointer to the head. */
	CNode* m_pNodeHead;
	/** Pointer to the tail. */
	CNode* m_pNodeTail;
	/** The count of nodes in the list. */
	int m_nCount;
	/** The freed node list internal. */
	CNode* m_pNodeFree;
	/** The block list internal. */ 
	struct CFX_Plex* m_pBlocks;
	/** The size in nodes of each block. */
	int m_nBlockSize;

	/**
	 * Allocate a new node.
	 *
	 * @param[in] pPrev		The pointer to the previous node.
	 * @param[in] pNext		The pointer to the next node.
	 * @return The pointer to the new node.
	 */
	CNode* NewNode(CNode* pPrev, CNode* pNext);
	/**
	 * Free a node.
	 *
	 * @param[in] pNode		The node pointer.
	 */
	void FreeNode(CNode* pNode);

public:
	/** The destructor. */
	~CFX_PtrList();
};

//*****************************************************************************
//* Utilities
//*****************************************************************************
/**
 * Prototype of callback function provided by custom module for deallocating private data.
 */
typedef void (*PD_CALLBACK_FREEDATA)(FX_LPVOID pData);

/**
 * @brief Private data structure.
 */
struct FX_PRIVATEDATA
{
	/**
	 * Free the private data pointed by m_pData.
	 */
	void					FreeData();

	/** Module ID */
	FX_LPVOID				m_pModuleId;
	/** Private data. */
	FX_LPVOID				m_pData;
	/** Pointer of a callback function provided by custom module for deallocating private data. */
	PD_CALLBACK_FREEDATA	m_pCallback;
	/** Is it using self destruct for private data ? 
	 * If TRUE, m_pData must point to a CFX_DestructObject derived object actually.
	 */
	FX_BOOL					m_bSelfDestruct;
};

/**
 * @brief Private data storage.
 */
class CFX_PrivateData
{
public:
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Construct with allocator. */
	CFX_PrivateData(IFX_Allocator* pAllocator = NULL) : m_DataList(pAllocator) {}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CFX_PrivateData() {}
	//<<<+++OPENSOURCE_END
#endif
	/** The destructor. */
	~CFX_PrivateData();

	/** Release all remaining data */
	void					ClearAll();

	/**
	 * Set private data.
	 * If the data points to an object that will belong to the attached object (which means
	 * when the attached object is destroyed, the private data should be destroyed too), then the caller
	 * must provide a callback for freeing the data.
	 * If the private data is just a number, or some external pointer, then the callback can be NULL.
	 *
	 * @note: this function will free any previously stored data for with same module ID.
	 *
	 * @param[in] module_id			The module id.
	 * @param[in] pData				The private data.
	 * @param[in] callback			The callback function for deallocating provided private data.				
	 */
	void					SetPrivateData(FX_LPVOID module_id, FX_LPVOID pData, PD_CALLBACK_FREEDATA callback);

	/**
	 * Set private object.
	 * The private object will become a part of the attached object, so when the attached object
	 * is destroyed, the private object will be destroyed too.
	 *
	 * @note: this function will free any previously stored data for with same module ID.
	 *
	 * @param[in] module_id			The module id.
	 * @param[in] pObj				The private data in fact a CFX_DestructObject derived object.
	 */
	void					SetPrivateObj(FX_LPVOID module_id, CFX_DestructObject* pObj);

	/**
	 * Get previously stored private data. Returns NULL for not stored.
	 * This function works for private data set by SetPrivateData() or SetPrivateObj().
	 *
	 * @param[in] module_id			The module id.
	 * @return The private data identified by provided module id.
	 */
	FX_LPVOID				GetPrivateData(FX_LPVOID module_id);

	/**
	 * Lookup a private data.
	 *
	 * @param[in] module_id			The module id.
	 * @param[out] pData			Private data.
	 * @return TRUE if exists, FALSE if not found.
	 */
	FX_BOOL					LookupPrivateData(FX_LPVOID module_id, FX_LPVOID &pData) const
	{
		if (!module_id) return FALSE;
		FX_DWORD nCount = m_DataList.GetSize();
		for (FX_DWORD n = 0; n < nCount; n ++) {
			if (m_DataList[n].m_pModuleId == module_id) {
				pData = m_DataList[n].m_pData;
				return TRUE;
			}
		}
		return FALSE;
	}

	/**
	 * Remove previously stored private data. FPDFAPI assumes the module has deallocated the data,
	 * so the free data callback will NOT be called.
	 *
	 * @param[in] module_id			The module id.
	 * @return TRUE if exists, FALSE if not found.
	 */
	FX_BOOL					RemovePrivateData(FX_LPVOID module_id);

protected:
	/** Private data array. */
	CFX_ArrayTemplate<FX_PRIVATEDATA>	m_DataList;
	/**
	 * Add a private data. Add if not exist, otherwise modify.
	 *
	 * @param[in] module_id			The module id.
	 * @param[in] pData				The private data.
	 * @param[in] callback			The callback function for deallocating provided private data.
	 * @param[in] bSelfDestruct		Whether the private data is a CFX_DestructObject derived object actually.
	 */
	void					AddData(FX_LPVOID module_id, FX_LPVOID pData, PD_CALLBACK_FREEDATA callback, FX_BOOL bSelfDestruct);
};

/**
 * @brief Bit stream, reading from a continuous bit stream (starting at byte boundary). 
 * Assuming number of bits in each unit is not larger than 32.
 */
class CFX_BitStream : public CFX_Object
{
public:
	/**
	 * Initialize the bit-stream with a memory block. Must call Init() first.
	 *
	 * @param[in] pData		Pointer to a memory block.
	 * @param[in] dwSize	The size in bytes of the memory block.
	 */
	void				Init(FX_LPCBYTE pData, FX_DWORD dwSize);
	
	/**
	 * Get specified number of bits (maximum 32 bits).
	 *
	 * @param[in] nBits			Specify the number of bits (maximum 32 bits).
	 * @return A FX_DWORD value.
	 */
	FX_DWORD			GetBits(FX_DWORD nBits);

	/**
	 * Get to byte boundary. If current bit position is not multiplication of 8, 
	 * the rest of the current byte will be skipped.
	 */
	void				ByteAlign();

	/**
	 * Check if reached end of the stream.
	 *
	 * @return Non-zero means it reached end of the stream, otherwise not.
	 */
	FX_BOOL				IsEOF() { return m_BitPos >= m_BitSize; }

	/**
	 * Skip a number of bits.
	 *
	 * @param[in] nBits		The number of bits to be skipped.
	 */
	void				SkipBits(FX_DWORD nBits) { m_BitPos += nBits; }

	/**
	 * Rewind a bit-stream. Simply set the current bit position to be zero.
	 */
	void				Rewind() { m_BitPos = 0; }

protected:
	/** Bit position (zero-based). */
	FX_DWORD			m_BitPos;
	/** Total bit counts in the memory block. */
	FX_DWORD			m_BitSize;
	/** bit-stream stream buffer. */
	FX_LPCBYTE			m_pData;
};

/**
 * @brief Accessor of reference counted object.
 * To use reference counted objects, application can use this template with particular object class.
 */
template <class ObjClass> class CFX_CountRef : public CFX_Object
{
public:
	/** It is used short for CFX_CountRef<ObjClass>. */
	typedef CFX_CountRef<ObjClass> Ref;

	/**
	 * @brief We define a class here derived from user data class, with an additional reference count member.
	 */
	class CountedObj : public ObjClass
	{
	public:
		/** The constructor. */
		CountedObj() {}
		/** The copy constructor. */
		CountedObj(const CountedObj& src) : ObjClass(src) {}

		/** The reference count. */
		int			m_RefCount;
	};

	/**
	 * Construct a null reference.
	 */
	CFX_CountRef() 
	{ 
		m_pObject = NULL; 
	}

	/**
	 * Copy constructor from another reference.
	 *
	 * @param[in] ref		The input reference.
	 */
	CFX_CountRef(const Ref& ref) 
	{
		m_pObject = ref.m_pObject; 
		if (m_pObject) m_pObject->m_RefCount ++; 
	}

	/**
	 * Destruct a reference and release the object it refers to.
	 */
	~CFX_CountRef() 
	{ 
		if (!m_pObject) return; 
		m_pObject->m_RefCount --;
		if (m_pObject->m_RefCount <= 0) delete m_pObject;
	}

	/**
	 * Create a new object and refer to it.
	 * The returned pointer to the object can be used to modify the content of objects.
	 *
	 * @return A modifiable object pointer.
	 */
	ObjClass*			New()
	{
		if (m_pObject) {
			m_pObject->m_RefCount --;
			if (m_pObject->m_RefCount <= 0) 
				delete m_pObject;
			m_pObject = NULL;
		}
		m_pObject = FX_NEW CountedObj;
		if (!m_pObject) return NULL;
		m_pObject->m_RefCount = 1;
		return m_pObject;
	}

	/**
	 * assignment(=) operator overload. Assign from another reference.
	 *
	 * @param[in] ref		The input reference.		
	 */
	void				operator = (const Ref& ref) 
	{
		if (ref.m_pObject)
			ref.m_pObject->m_RefCount ++;
		if (m_pObject) {
			m_pObject->m_RefCount --;
			if (m_pObject->m_RefCount <= 0) 
				delete m_pObject;
		}
		m_pObject = ref.m_pObject;
	}

	/**
	 * assignment(=) operator overload. Assign from a typeless pointer.
	 * 
	 * @note p must be 0.
	 *
	 * @param[in] p		It must be zero. Other value is not valid.
	 */
	void				operator = (void* p) 
	{
		FXSYS_assert(p == 0);
		if (m_pObject == NULL) return;
		m_pObject->m_RefCount --;
		if (m_pObject->m_RefCount <= 0) 
			delete m_pObject;
		m_pObject = NULL; 
	}

	#ifndef _FXM_OPENSOURCE_
		//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
		#if defined(_FX_MANAGED_CODE_) && defined(GetObject)
			#undef GetObject
		#endif
		//<<<+++OPENSOURCE_MUST_END
	#endif
	/**
	 * Get a pointer of constant object. This pointer can't be used to alter the object content.
	 *
	 * @return A pointer to the constant object.
	 */
	const ObjClass*		GetObject() const 
	{ 
		return m_pObject; 
	}
	/**
	 * This casting operator get a pointer of the constant object.
	 *
	 * @return A pointer to the constant object.
	 */
	operator			const ObjClass*() const 
	{ 
		return m_pObject; 
	}

	/**
	 * Is the pointer of the object null ? 
	 *
	 * @return Non-zero means null, otherwise not null.
	 */
	FX_BOOL				IsNull() const 
	{ 
		return m_pObject == NULL; 
	}
	/**
	 * Is the pointer of the object not null ?
	 *
	 * @return Non-zero means not null, otherwise null.
	 */
	FX_BOOL				NotNull() const 
	{ 
		return m_pObject != NULL; 
	}

	/**
	 * Get a modifiable copy of the object. 
	 * If the reference was refer to null, then a new object will be created.
	 * The returned pointer can be used to alter the object content.
	 *
	 * @return A pointer to the object.
	 */
	ObjClass*			GetModify()
	{
		if (m_pObject == NULL) {
			m_pObject = FX_NEW CountedObj;
			if (m_pObject)
				m_pObject->m_RefCount = 1;
		} else if (m_pObject->m_RefCount > 1) {
			m_pObject->m_RefCount --;
			CountedObj* pOldObject = m_pObject;
			m_pObject = NULL;
			m_pObject = FX_NEW CountedObj(*pOldObject);
			if (m_pObject)
				m_pObject->m_RefCount = 1;
		}
		return m_pObject;
	}

	/**
	 * Set the pointer of the object to be null.
	 */
	void				SetNull() 
	{
		if (m_pObject == NULL) return;
		m_pObject->m_RefCount --;
		if (m_pObject->m_RefCount <= 0) 
			delete m_pObject;
		m_pObject = NULL; 
	}

	/**
	 * comparison(!=) operator overload. Compare with another reference.
	 *
	 * @return Non-zero means equal, otherwise not equal.
	 */
	FX_BOOL				operator == (const Ref& ref) const 
	{ 
		return m_pObject == ref.m_pObject; 
	}

protected:
	/** Reference counted object internal. */
	CountedObj*			m_pObject;
};

/**
 * @brief Simple pause interface.
 */
class IFX_Pause
{
public:
	/**
	 * Do we need to pause now ?
	 *
	 * @return Non-zero means we need, otherwise we need not.
	 */
	virtual FX_BOOL	NeedToPauseNow() = 0;
};

/**
 * @brief Base class for data filters. A data filter takes some input data and outputs to another
 * filter, or the final destination buffer.
 */
class CFX_DataFilter : public CFX_Object
{
public:
	/** The destructor. Destroy this filter and all its chain. */
	virtual ~CFX_DataFilter();

	/**
	 * Set destination filter. Note the filter will be appended to the end of current filter chain.
	 *
	 * @param[in] pFilter		The input data filter.
	 */
	void			SetDestFilter(CFX_DataFilter* pFilter);

	/**
	 * Detect EOF.
	 *
	 * @return Non-zero means it met EOF, otherwise not.
	 */
	FX_BOOL			IsEOF() const { return m_bEOF; }

	/**
	 * Get current position in the source stream (byte offset from the beginning of all input data).
	 *
	 * @return The current position in the source stream.
	 */
	FX_DWORD		GetSrcPos() { return m_SrcPos; }

	/**
	 * Input a data block to the filter (and its filter chain), and receive the final output.
	 *
	 * @param[in] src_buf		The input data block.
	 * @param[in] src_size		The size in bytes of the input data block.
	 * @param[out] dest_buf		It receives the output data.
	 */
	void			FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf);

	/**
	 * Indicate the input finished.
	 * For some filters, there might be some last output generated.
	 *
	 * @param[out] dest_buf		It receives the output data.
	 */
	void			FilterFinish(CFX_BinaryBuf& dest_buf);

protected:
	/** The constructor. */
	CFX_DataFilter();

	virtual void	v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf) = 0;
	virtual void	v_FilterFinish(CFX_BinaryBuf& dest_buf) = 0;
	void			ReportEOF(FX_DWORD left_input);

	/** Indicate whether we met the EOF. */
	FX_BOOL			m_bEOF;
	/** Current position in the source stream. */
	FX_DWORD		m_SrcPos;
	/** Filter chain. */
	CFX_DataFilter*	m_pDestFilter;
};

/** 
* @brief The smart pointer.
*/
template <class T>
class CFX_SmartPointer
{
public:
	CFX_SmartPointer(T *pObj) : m_pObj(pObj) {}
	~CFX_SmartPointer() {m_pObj->Release();}

			operator T*(void)	{return m_pObj;}
    T&		operator *(void)	{return *m_pObj;}
    T*		operator ->(void)	{return m_pObj;}

protected:
	T *m_pObj;
};

#define FX_DATALIST_LENGTH	1024

/** 
* @brief The sorted list array template
*/
template<size_t unit>
class CFX_SortListArray : public CFX_Object
{
protected:
	/** The data list. */
	struct DataList {
		/** The start index. */
		FX_INT32	start;
		/** The data count. */
		FX_INT32	count;
		FX_LPBYTE	data;
	};

public:
	/** The constructor. */
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CFX_SortListArray(IFX_Allocator* pAllocator = NULL) : m_CurList(0), m_DataLists(pAllocator) {}
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_SortListArray() : m_CurList(0) {}
	//<<<+++OPENSOURCE_END
#endif
	/** The destructor. */
	~CFX_SortListArray()
	{
		Clear();
	}
	
	/** Clear the data list. */
	void			Clear()
	{
#ifndef _FXM_OPENSOURCE_
		//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
		IFX_Allocator* pAllocator = m_DataLists.m_pAllocator;
		//<<<+++OPENSOURCE_END
#endif
		for (FX_INT32 i = m_DataLists.GetUpperBound(); i >= 0; i--){
			DataList list = m_DataLists.ElementAt(i);
#ifndef _FXM_OPENSOURCE_
			//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
			if (list.data) FX_Allocator_Free(pAllocator, list.data);
			//<<<+++OPENSOURCE_END
#else
			//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
			if (list.data) FX_Free(list.data);
			//<<<+++OPENSOURCE_END
#endif
		}
		m_DataLists.RemoveAll();
		m_CurList = 0;
	}

	/**
	 * Append a list data
	 *
	 * @param[in] nStart		The start index of data
	 * @param[in] nCount		The count of data
	 */
	void			Append(FX_INT32 nStart, FX_INT32 nCount)
	{
		if (nStart < 0) return;
#ifndef _FXM_OPENSOURCE_
		//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
		IFX_Allocator* pAllocator = m_DataLists.m_pAllocator;
		//<<<+++OPENSOURCE_END
#endif
		while (nCount > 0){
			FX_INT32 temp_count = FX_MIN(nCount, FX_DATALIST_LENGTH);
			DataList list;
#ifndef _FXM_OPENSOURCE_
			//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
			list.data = FX_Allocator_Alloc(pAllocator, FX_BYTE, temp_count * unit);
			//<<<+++OPENSOURCE_END
#else
			//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
			list.data = FX_Alloc(FX_BYTE, temp_count * unit);
			//<<<+++OPENSOURCE_END
#endif
			if (!list.data) break;
			FXSYS_memset32(list.data, 0, temp_count * unit);
			list.start = nStart;
			list.count = temp_count;

			Append(list);
			nCount -= temp_count;
			nStart += temp_count;
		}
	}

	/**
	 * Get the data.
	 *
	 * @param[in] nIndex		The data index.
	 */
	FX_LPBYTE		GetAt(FX_INT32 nIndex)
	{
		if (nIndex < 0) return NULL;
		if (m_CurList < 0 || m_CurList >= m_DataLists.GetSize()) return NULL;
		DataList *pCurList = m_DataLists.GetDataPtr(m_CurList);
		if (!pCurList || nIndex < pCurList->start || nIndex >= pCurList->start + pCurList->count){
			pCurList = NULL;
			FX_INT32 iStart = 0;
			FX_INT32 iEnd = m_DataLists.GetUpperBound();
			FX_INT32 iMid = 0;
			while (iStart <= iEnd){
				iMid = (iStart + iEnd) / 2;
				DataList* list = m_DataLists.GetDataPtr(iMid);
				if (nIndex < list->start)
					iEnd = iMid - 1;
				else if (nIndex >= list->start + list->count)
					iStart = iMid + 1;
				else {
					pCurList = list;
					m_CurList = iMid;
					break;
				}
			}
		}
		return pCurList ? pCurList->data + (nIndex - pCurList->start) * unit : NULL;
	}

protected:
	void			Append(const DataList& list)
	{
		FX_INT32 iStart = 0;
		FX_INT32 iEnd = m_DataLists.GetUpperBound();
		FX_INT32 iFind = 0;
		while (iStart <= iEnd){
			FX_INT32 iMid = (iStart + iEnd) / 2;
			DataList* cur_list = m_DataLists.GetDataPtr(iMid);
			if (list.start < cur_list->start + cur_list->count)
				iEnd = iMid - 1;
			else{
				if (iMid == iEnd){
					iFind = iMid + 1;
					break;
				}
				DataList* next_list = m_DataLists.GetDataPtr(iMid + 1);
				if (list.start < next_list->start){
					iFind = iMid + 1;
					break;
				} else {
					iStart = iMid + 1;
				}
			}
		}
		m_DataLists.InsertAt(iFind, list);
	}

	FX_INT32		m_CurList;
	CFX_ArrayTemplate<DataList>	m_DataLists;
};

template<typename T1, typename T2>
class CFX_ListArrayTemplate : public CFX_Object
{
public:
	/**
	 * Clear data.
	 */
	void			Clear()
	{
		m_Data.Clear();
	}

	/**
	 * add a list data
	 *
	 * @param[in] nStart		The start index of data
	 * @param[in] nCount		The count of data
	 */
	void			Add(FX_INT32 nStart, FX_INT32 nCount)
	{
		m_Data.Append(nStart, nCount);
	}

	/**
	 * Subscript([]) operator overload. 
	 *
	 * @param[in] nIndex	The data index.
	 */
	T2&				operator [] (FX_INT32 nIndex)
	{
		FX_LPBYTE data = m_Data.GetAt(nIndex);
		FXSYS_assert(data != NULL);

		return (T2&)(*(volatile T2*)data);
	}

	/**
	 * Get a point to data.
	 *
	 * @param[in] nIndex	The data index.
	 */
	T2*				GetPtrAt(FX_INT32 nIndex)
	{
		return (T2*)m_Data.GetAt(nIndex);
	}
protected:
	T1			m_Data;
};

typedef CFX_ListArrayTemplate<CFX_SortListArray<sizeof(FX_FILESIZE)>, FX_FILESIZE>	CFX_FileSizeListArray;
typedef CFX_ListArrayTemplate<CFX_SortListArray<sizeof(FX_DWORD)>, FX_DWORD>		CFX_DWordListArray;

typedef enum {
    Ready,              /**< Ready. */
    ToBeContinued,		/**< To be continued. */
    Found,				/**< Found. */
    NotFound,           /**< Not found. */
    Failed,				/**< Failed. */
    Done                /**< Done. */
} FX_ProgressiveStatus;
#define ProgressiveStatus	FX_ProgressiveStatus

#ifdef _FX_NO_NAMESPACE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
#define FX_NAMESPACE_DECLARE(namespace, type)       type
//<<<+++OPENSOURCE_END
#else
//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
#define FX_NAMESPACE_DECLARE(namespace, type)       namespace::type
//<<<+++OPENSOURCE_END
#endif

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT

//*****************************************************************************
//* Unknown object
//*****************************************************************************
class IFX_Unknown
{
public:
	//Decrements reference count and release the current object
	virtual FX_DWORD	Release() = 0;
	//Increments reference count
	virtual FX_DWORD	AddRef() = 0;
};

//Judge an integer is odd or even
#define FX_IsOdd(a)	((a) & 1)

//<<<+++OPENSOURCE_MUST_END
#endif

//<<<+++OPENSOURCE_MUST_BEGIN
#endif // _FX_BASIC_H_
//<<<+++OPENSOURCE_MUST_END

/** @} */

//<<<+++OPENSOURCE_END
